<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>动态日历选择器</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
      background-color: #f7f7f7;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      padding: 20px;
    }
    
    .calendar-picker {
      width: 10rem;
      height: 14.7733rem;
      background-color: #ffffff;
      position: relative;
      border-radius: 0.2667rem;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
      overflow: hidden;
      display: flex;
      flex-direction: column;
    }

    .calendar-picker-header {
      width: 10rem;
      height: 3.1467rem;
      background-color: #ffffff;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: space-around;
      border-bottom: 1px solid #eee;
    }

    .calendar-picker-header-title {
      font-size: 0.48rem;
      color: #000;
      font-weight: 500;
    }

    .calendar-picker-header-center {
      font-size: 0.48rem;
      color: #000;
      font-weight: 500;
    }

    .calendar-picker-header-buttom {
      width: 10rem;
      height: 1.0667rem;
      box-sizing: border-box;
    }

    .calendar-picker-header-buttom ul {
      width: 10rem;
      height: 1.0667rem;
      display: flex;
      align-items: center;
      justify-content: space-around;
      list-style: none;
    }

    .calendar-picker-header-buttom li {
      font-size: 0.4267rem;
      color: #000;
      width: 14.28%;
      text-align: center;
    }

    .calendar-picker-content {
      width: 10rem;
      height: 8.1867rem;
      background-color: #ffffff;
      overflow: auto;
      display: flex;
      flex-direction: column;
      margin-top: 0.4rem;
    }

    .month-container {
      margin-bottom: 0.4rem;
    }

    .calendar-picker-content-title {
      width: 10rem;
      height: 1.0667rem;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 0.4267rem;
      color: #000;
      font-weight: 500;
      background-color: #f8f8f8;
      position: sticky;
      top: 0;
      z-index: 10;
    }

    .calendar-picker-content-top {
      width: 10rem;
      margin-top: 0.2667rem;
    }

    .calendar-picker-content-top ul {
      width: 10rem;
      display: flex;
      flex-wrap: wrap;
      list-style: none;
    }

    .calendar-picker-content-top li {
      width: 1.42rem;
      height: 1.44rem;
      font-size: 0.4267rem;
      color: #000;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 0.1rem;
      margin: 0.05rem;
    }

    .calendar-picker-content-top li.empty {
      visibility: hidden;
    }

    .calendar-picker-content-top li.today {
      background-color: #ee0a24;
      color: white;
    }

    .calendar-picker-content-bottom {
      width: 10rem;
      height: 1.0667rem;
      background-color: #ffffff;
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 0.2rem 0;
      border-top: 1px solid #eee;
    }

    .calendar-picker-content-bottom button {
      width: 9rem;
      background-color: #ee0a24;
      height: 1.0667rem;
      font-size: 0.4267rem;
      border: 0;
      border-radius: 1rem;
      color: white;
      font-weight: 500;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div id="app">
    <!-- 日历选择器 -->
    <div class="calendar-picker">
      <div class="calendar-picker-header">
        <div class="calendar-picker-header-title">
          <span>日期选择</span>
        </div>
        <div class="calendar-picker-header-center">
          <!-- 动态显示当前可视区域的年月 -->
          <span>{{ visibleYear }}年{{ visibleMonth + 1 }}月</span>
        </div>
        <div class="calendar-picker-header-buttom">
          <ul>
            <li>日</li>
            <li>一</li>
            <li>二</li>
            <li>三</li>
            <li>四</li>
            <li>五</li>
            <li>六</li>
          </ul>
        </div>
      </div>
      <div class="calendar-picker-content" ref="content" @scroll="handleScroll">
        <div v-for="(monthData, index) in allMonthsData" :key="index" class="month-container" :ref="'month-' + index">
          <div class="calendar-picker-content-title">
            <p>{{ monthData.year }}年{{ monthData.month + 1 }}月</p>
          </div>
          <div class="calendar-picker-content-top">
            <ul>
              <li 
                v-for="(date, dateIndex) in monthData.days" 
                :key="dateIndex" 
                :class="{ 'empty': !date.isCurrentMonth, 'today': date.isToday }"
              >
                {{ date.day || '' }}
              </li>
            </ul>
          </div>
        </div>
      </div>
      <div class="calendar-picker-content-bottom">
        <button>确认</button>
      </div>
    </div>
  </div>

  <script>
    new Vue({
      el: '#app',
      data() {
        return {
          allMonthsData: [], // 存储所有月的日历数据
          currentYear: new Date().getFullYear(), // 当前年份
          currentMonth: new Date().getMonth(), // 当前月份（0-11）
          startYear: 2020, // 起始年份
          visibleYear: new Date().getFullYear(), // 当前可视区域的年份
          visibleMonth: new Date().getMonth(), // 当前可视区域的月份
          monthPositions: [] // 存储每个月份元素的位置信息
        }
      },
      mounted() {
        // 组件初始化时，生成起始年到当前年今月前的所有月的日历
        this.generateAllMonthsCalendar();
        
        // 添加短暂延迟确保DOM已完全渲染
        setTimeout(() => {
          this.calculateMonthPositions();
          this.scrollToBottom();
        }, 100);
        
        // 添加窗口大小变化事件监听
        window.addEventListener('resize', this.calculateMonthPositions);
      },
      beforeDestroy() {
        // 移除事件监听
        window.removeEventListener('resize', this.calculateMonthPositions);
      },
      methods: {
        isToday(date) {
          const today = new Date();
          return date.getFullYear() === today.getFullYear() &&
            date.getMonth() === today.getMonth() &&
            date.getDate() === today.getDate();
        },
        generateAllMonthsCalendar() {
          const now = new Date();
          const currentYearVal = now.getFullYear();
          const currentMonthVal = now.getMonth();
          const monthsData = [];

          // 遍历起始年到当前年
          for (let year = this.startYear; year <= currentYearVal; year++) {
            // 如果是当前年，只生成到今月前一个月的数据包括本月
            const endMonth = year === currentYearVal ? currentMonthVal + 1 : 12;
            for (let month = 0; month < endMonth; month++) {
              const firstDay = new Date(year, month, 1);
              const lastDay = new Date(year, month + 1, 0);
              const firstDayOfWeek = firstDay.getDay();
              const daysInMonth = lastDay.getDate();

              const days = [];

              // 填充当前月之前的空白日期
              for (let i = 0; i < firstDayOfWeek; i++) {
                days.push({ day: '', isCurrentMonth: false });
              }

              // 填充当前月的日期
              for (let i = 1; i <= daysInMonth; i++) {
                const date = new Date(year, month, i);
                days.push({
                  day: i,
                  isCurrentMonth: true,
                  isToday: this.isToday(date),
                  date: date
                });
              }

              monthsData.push({
                year: year,
                month: month,
                days: days
              });
            }
          }

          this.allMonthsData = monthsData.reverse();
        },
        calculateMonthPositions() {
          // 计算每个月份元素的位置
          this.monthPositions = [];
          this.allMonthsData.forEach((month, index) => {
            const element = this.$refs[`month-${index}`][0];
            if (element) {
              const rect = element.getBoundingClientRect();
              const contentRect = this.$refs.content.getBoundingClientRect();
              this.monthPositions.push({
                top: rect.top - contentRect.top + this.$refs.content.scrollTop,
                height: rect.height,
                year: month.year,
                month: month.month
              });
            }
          });
        },
        handleScroll() {
          // 获取滚动容器的滚动位置
          const scrollTop = this.$refs.content.scrollTop;
          const containerHeight = this.$refs.content.clientHeight;
          
          // 计算中间位置
          const middlePoint = scrollTop + containerHeight / 2;
          
          // 找到当前中间位置对应的月份
          for (let i = 0; i < this.monthPositions.length; i++) {
            const position = this.monthPositions[i];
            if (middlePoint >= position.top && middlePoint <= position.top + position.height) {
              this.visibleYear = position.year;
              this.visibleMonth = position.month;
              break;
            }
          }
        },
        scrollToBottom() {
          // 滚动到最底部，显示最近的月份
          this.$refs.content.scrollTop = this.$refs.content.scrollHeight;
        }
      }
    });
  </script>
</body>
</html>